﻿//2024-2-6 Tuesday 15:36:25
//#include <stdio.h>
//
//int main()
//{
//	//数组名的理解：
//	//数组名是数组首元素的地址
//	//但是有2个例外：
//	//1. sizeof(数组名)
//	//2. &数组名
//
//	char arr[] = { 'a','b','c','d','e','f' };
//
//	//在sizeof停留可以看到返回值类型，这里是：unsigned long long
//	//所以打印的时候可以用：%llu/%zu
//
//	printf("%zu\n", sizeof(arr)); //6
//	printf("%llu\n", sizeof(arr + 0)); //4/8 地址
//	printf("%llu\n", sizeof(*arr)); //1
//	printf("%llu\n", sizeof(arr[1])); //1
//	printf("%llu\n", sizeof(&arr)); //4/8
//	printf("%llu\n", sizeof(&arr + 1)); //4/8
//	printf("%llu\n", sizeof(&arr[0] + 1));//4/8
//
//	return 0;
//}


//第15讲：深⼊理解指针(5)
//⽬录
//1. sizeof和strlen的对⽐
//2. 数组和指针笔试题解析
//3. 指针运算笔试题解析

//2. 数组和指针笔试题解析
//2.2 字符数组
//#include <stdio.h>
//#include <string.h>
//
//int main()
//{
//	char arr[] = { 'a','b','c','d','e','f' };
//	//              0   1   2
//
//	printf("%zd\n", strlen(arr)); //随机值
//	//因为数组中没有明确给出\0
//
//	printf("%zd\n", strlen(arr + 0)); //随机值
//
//	printf("%zd\n", strlen(*arr)); //'a'的ascll是十进制的97，因为strlen的参数是const char* str，把97看作是一个地址了，非法访问
//	                               //My understanding: 你不能随便访问，除非是在你创建的空间内
//	//*arr -->'a' -- 97//非法访问的-err	
//
//	printf("%zd\n", strlen(arr[1])); //'b'，非法访问
//	//'b' ->98 //err - 非法访问
//
//	printf("%zd\n", strlen(&arr)); //随机值
//	//&arr                 const char*
//	//char(*p)[6]    强转   const char*
//
//	printf("%zd\n", strlen(&arr + 1)); //随机值
//
//	printf("%zd\n", strlen(&arr[0] + 1)); //随机值
//
//	return 0;
//}


//#include <stdio.h>
//
//int main()
//{
//	char arr[] = "abcdef";
//
//	printf("%llu\n", sizeof(arr)); //7 (6 - error)
//	//不好意思忘了\0                 
//	printf("%llu\n", sizeof(arr + 0)); //4/8
//	//arr表示数组首元素的地址
//	//arr+0还是首元素的地址，大小就是4/8个字节
//
//	printf("%llu\n", sizeof(*arr)); //1
//	//arr表示数组首元素的地址
//	//*arr就是首元素，大小就是1字节
//
//	printf("%llu\n", sizeof(arr[1])); //1
//	//arr[1]是第2个元素，大小也是1字节
//
//	printf("%llu\n", sizeof(&arr)); //4/8
//	//&arr是数组的地址，但是也是地址，是地址大小就是4/8个字节
//
//	printf("%llu\n", sizeof(&arr + 1)); //4/8(非法访问 - error)
//	//不好意思，看成了strlen，数组的地址 + 1之后还是地址，是地址就是4/8个字节
//	//&arr是数组的地址，&arr+1就是跳过整个数组的那个地址
//
//	printf("%llu\n", sizeof(&arr[0] + 1)); //4/8
//	//第2个元素的地址，大小是4/8个字节
//
//	return 0;
//}


//#include <stdio.h>
//#include <string.h>
//
//int main()
//{
//	char arr[] = "abcdef";
//
//	//对于strlen的返回值打印可以写成 %lld
//	//上面sizeof就是                %llu
//
//	printf("%lld\n", strlen(arr)); //6
//	//arr是数组首元素的地址
//
//	printf("%lld\n", strlen(arr + 0)); //6
//	//arr+0也是数组首元素的地址
//
//	printf("%lld\n", strlen(*arr)); //注意strlen的参数类型是：const char* str，'a'非法访问
//	//err - 非法访问
//	printf("%lld\n", strlen(arr[1])); //'b'非法访问
//
//	//err - 非法访问
//	printf("%lld\n", strlen(&arr)); //6
//	//6, &arr是数组的地址，但是这个地址也是指向数组的起始位置的
//	//strlen就从起始位置开始向后找\0
//	//也就是说：指向数组的地址也是指向数组首元素的地址，只不过类型不一样罢了，地址的值是一样的
//	//size_t strlen (const char* str)  后面数组指针类型会强转为字符类型，编译器在编译的过程中自己转
//	//还有就是：你传谁的地址就从谁的地址开始数，直到数到\0
//
//	printf("%lld\n", strlen(&arr + 1)); //随机值
//	//是跳过整个数组后的地址，从这里开始向后找\0，就是随机值
//
//	printf("%lld\n", strlen(&arr[0] + 1)); //5
//	//&arr[0]+1是第2个元素的地址，长度是5
//
//	return 0;
//}


//#include <stdio.h>
//
//int main()
//{
//	char* p = "abcdef";
//	//因为字符串是一块连续的空间，所以可以看成一个伪数组，所以可以通过下标访问
//
//	printf("%llu\n", sizeof(p)); //4/8
//	//p是一个指针变量，大小是4/8个字节
//
//	printf("%llu\n", sizeof(p + 1)); //4/8
//	//p+1是'b'的地址，是地址就是4/8个字节
//
//	printf("%llu\n", sizeof(*p)); //1
//	//*p是首字符，大小是1字节
//
//	printf("%llu\n", sizeof(p[0])); //1
//	//p[0] == *(p+0)，其实就是字符串中的首字符，大小是1字节
//	
//	printf("%llu\n", sizeof(&p)); //4/8
//	//&p是p的地址，也是地址，地址的大小就是4/8个字节
//
//	printf("%llu\n", sizeof(&p + 1)); //4/8
//	//&p+1也是地址，&p+1是跳过p变量后的地址
//
//	printf("%llu\n", sizeof(&p[0] + 1)); //4/8
//	//4/8 - &p[0]+1是b的地址
//	//[]优先级 > &
//
//	return 0;
//}


//#include <stdio.h>
//
//int main()
//{
//	printf("%c\n", "abcdef"[0]);
//	printf("%c\n", "abcdef"[1]);
//
//	return 0;
//}


//20:57:50
//#include <stdio.h>
//#include <string.h>
//
//int main()
//{
//	//打印的时候用%d，换成x86就不会报警告
//	char* p = "abcdef";
//	//char* p = "abcdefghi"; //换成这样也是随机值
//
//	printf("%lld\n", strlen(p)); //6
//	//字符串中有\0，p存放的是a的地址，从a的地址开始向后访问
//
//	printf("%lld\n", strlen(p + 1)); //5
//
//	//printf("%lld\n", strlen(*p)); //非法访问
//	//err
//
//	//printf("%lld\n", strlen(p[0])); //非法访问
//	//err
//	//*p==*(p+0) == p[0]
//
//	printf("%lld\n", strlen(&p)); //随机值
//	//&p是p的地址，从p所占空间的起始位置开始查找的
//
//	printf("%lld\n", strlen(&p + 1)); // 随机值
//
//	printf("%lld\n", strlen(&p[0] + 1)); //5
//
//	return 0;
//}



//第15讲：深⼊理解指针(5)
//⽬录
//1. sizeof和strlen的对⽐
//2. 数组和指针笔试题解析
//3. 指针运算笔试题解析

//2. 数组和指针笔试题解析
//2.3 ⼆维数组
//#include <stdio.h>
//
//int main()
//{
//	int a[3][4] = { 0 };
//
//	printf("%llu\n", sizeof(a)); //48
//	//计算的是整个二维数组的大小，单位是字节 - 48
//
//	printf("%llu\n", sizeof(a[0][0])); //4
//	//a[0][0]是数组第一行第一个元素，大小是4个字节
//
//	printf("%llu\n", sizeof(a[0])); //16
//	//a[0]其实就是第一行的数组名
//	//这里的第一行的数组名单独放在sizeof内部了，计算的是第一行的大小
//
//	printf("%llu\n", sizeof(a[0] + 1)); //4/8
//	//a[0]是第一行这个数组的数组名，但是数组名并非单独放在sizeof内部，所以数组名表示数组首元素的地址
//	//也就是a[0][0]的地址，a[0] + 1是第一行第二个元素（a[0][1]）的地址
//	//地址的大小是4/8个字节
//
//	printf("%llu\n", sizeof(*(a[0] + 1))); //4 (16 - error)
//	//首先a[0] + 1是&a[0][1]，我搞混淆了，太乱了
//	//a[0] + 1是第一行第2个元素（a[0][1]）的地址
//	//*(a[0]+1)就是第一行第2个元素，大小是4个字节
//
//	printf("%llu\n", sizeof(a + 1));//4/8
//	//a没有单独放在sizeof内部，没有&，数组名a就是数组首元素的地址，也就是第一行的地址
//	//a+1就是第2行的地址
//	//a -- int(*p)[4]
//	//a+1 -- int(*p)[4]
//
//	printf("%llu\n", sizeof(*(a + 1))); //16
//	//等价printf("%llu\n", sizeof(a[1]);
//	//*(a+1) == a[1]
//
//	printf("%llu\n", sizeof(&a[0] + 1)); //4/8
//	//a[0]是第一行的数组名，&a[0]取出的是第一行的地址，&a[0] + 1 得到的就是第2行的地址
//	//&a[0] + 1
//	//等价于a + 1
//
//	printf("%llu\n", sizeof(*(&a[0] + 1))); //16
//
//	printf("%llu\n", sizeof(*a)); //16
//	//数组名a就是数组首元素的地址，也是第一行的地址，*a就是第一行
//	//*a == *(a+0) == a[0]
//
//	printf("%llu\n", sizeof(a[3])); //16
//	//a[3] 和普通的 arr[3]一样
//
//	return 0;
//}


//2024-2-18 Sunday 18:12:42 
//第15讲：深⼊理解指针(5)
//⽬录
//1. sizeof和strlen的对⽐
//2. 数组和指针笔试题解析
//3. 指针运算笔试题解析

//3. 指针运算笔试题解析
//3.1 题⽬1：

//#include <stdio.h>
//int main()
//{
//	int a[5] = { 1, 2, 3, 4, 5 }; 
//	int* ptr = (int*)(&a + 1);
//	printf("%d,%d", *(a + 1), *(ptr - 1));
//	return 0;
//}
//程序的结果是什么？
//2        5


//3.2 题⽬2
//在X86环境下
//假设结构体的⼤⼩是20个字节
//程序输出的结构是啥？

//struct Test
//{
//	int Num;
//	char* pcName;
//	short sDate;
//	char cha[2];
//	short sBa[4];
//}*p = (struct Test*)0x100000;
//
//int main()
//{
//	printf("%p\n", p + 0x1); //+1到底+几？ 加10进制的20，即16进制中的14 //0x00100014，自动补0
//	printf("%p\n", (unsigned long)p + 0x1); //长整型：  0x001000001
//	printf("%p\n", (unsigned int*)p + 0x1); //整型指针：0x001000004
//	return 0;
//}


//后期再讲
//3.3 题⽬3
//#include <stdio.h>
//int main()
//{
//	int a[4] = { 1, 2, 3, 4 };
//	int* ptr1 = (int*)(&a + 1);
//	int* ptr2 = (int*)((int)a + 1);
//	printf("%x,%x", ptr1[-1], *ptr2);
//	return 0;
//}


//3.4 题⽬4
//#include <stdio.h>
//
//int main()
//{
//	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
//	//1 3
//	//5 0
//	//0 0
//
//	int* p;
//	p = a[0]; 
//
//	printf("%d", p[0]); //*p      1
//
//	return 0;
//}


//3.5 题⽬5
//假设环境是x86环境，程序输出的结果是啥？
//最好就画图理解
//#include <stdio.h>
//
//int main()
//{
//	int a[5][5]; //a[4][4]
//	int(*p)[4];
//	p = a; //a[0]
//
//	printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
//
//	return 0;
//}


//3.6 题⽬6
//#include <stdio.h>
//
//int main()
//{
//	int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
//	int* ptr1 = (int*)(&aa + 1); //跳过整个数组的地址
//	int* ptr2 = (int*)(*(aa + 1)); //把6强转为int*？error， 其实是*(aa+1) == aa[1]是数组第2个元素的地址
//
//	printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));
//	              //10             5
//
//	return 0;
//}


//3.7 题⽬7
//#include <stdio.h>
//
//int main()
//{
//	char* a[] = { "work","at","alibaba" }; //w        a           a      的地址
//	char** pa = a;                         //w的地址是char*放到char**里去
//	pa++;                                  //char** + 1指向a，为什么？
//
//	printf("%s\n", *pa);// %s往后打印，直到\0
//	              //at
//
//	return 0;
//}


//3.8 题⽬8
//画图理解
//有点复杂
#include <stdio.h>

int main()
{
	char* c[] = { "ENTER","NEW","POINT","FIRST" };
	char** cp[] = { c + 3,c + 2,c + 1,c };
	              //F     P     N     E    的地址
	char*** cpp = cp;
	              //F                      的地址

	printf("%s\n", **++cpp); //POINT
	printf("%s\n", *-- * ++cpp + 3); //ER
	printf("%s\n", *cpp[-2] + 3);
	                //**(cpp-2)+3     //ST
	printf("%s\n", cpp[-1][-1] + 1);
                    //*(*(cpp-1)-1)+1  EW
	return 0;
}
//





//2024-2-18 Sunday 21:54:04
//指针告一段落
